package com.ai.bitcoin.service.helper;

import com.ai.bitcoin.constant.CodeConstant;
import com.ai.bitcoin.constant.QrCodeConstant;
import com.ai.bitcoin.constant.RedisKeyInfo;
import com.ai.bitcoin.constant.WeiXinConfig;
import com.ai.bitcoin.exception.BusinessException;
import com.ai.bitcoin.util.GsonUtil;
import com.ai.bitcoin.util.HttpClientUtils;
import com.ai.bitcoin.util.IdGeneration;
import com.alibaba.fastjson.JSONObject;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Component
@Slf4j
public class WeiXinServiceHelper {

    private static final String JSAPI_TYPE = "jsapi";

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Value("${app.id}")
    private String APPID;

    @Value("${app.secret}")
    private String APPSERECT;

    private static final Map<String, String> headerMap = new HashMap<String, String>();

    static {
        headerMap.put("Content-Type", "application/json");
    }

    //获取普通access_token
    public String getWeiXinAccessToken() {

        String token = stringRedisTemplate.opsForValue().get(RedisKeyInfo.WX_ACCESS_TOKEN.key());
        if (token == null) {
            StringBuilder weixinTokenUrl = new StringBuilder(
                    WeiXinConfig.ACCESS_TOKEN);
            weixinTokenUrl.append("&appid=").append(APPID).append("&secret=")
                    .append(APPSERECT);

            if (log.isDebugEnabled()) {
                log.debug("weixin access token url { " + weixinTokenUrl.toString() + " }");
            }

            String resp = null;
            try {
                resp = com.ai.bitcoin.utils.HttpClientUtils.doGet(weixinTokenUrl.toString());
            } catch (Exception e) {
                log.error("get weixin access token occured error { appid=" + APPID + " ,appsecret=" + APPSERECT + " } ", e);
                throw new RuntimeException("get weixin access token occured error");
            }

            Map<String, Object> map = GsonUtil.fronJson2Map(resp);
            if (map.containsKey("errcode")) {
                log.error("获取accessToken失败-->errorcode:" + map.get("errcode") + "-->errmsg:" + map.get("errmsg"));
                return null;
            }
            else {
                token = String.valueOf(map.get("access_token"));
                Long expiresIn = Long.valueOf(String.valueOf(map.get("expires_in"))) - 1800;
                stringRedisTemplate.opsForValue().set(RedisKeyInfo.WX_ACCESS_TOKEN.key(), token, expiresIn, RedisKeyInfo.WX_ACCESS_TOKEN.unit());
                return token;
            }
        }
        else {
            return token;
        }


    }

    //获取网页授权access_token以及openId
    public Map<String, String> getWeiXinAuthAccessToken(String code) {
        StringBuilder wxAuthTokenUrl = new StringBuilder(WeiXinConfig.GET_AUTH_TOKEN);
        wxAuthTokenUrl.append("?appid=").append(APPID).append("&secret=").append(APPSERECT)
                .append("&code=").append(code).append("&grant_type=authorization_code");
        JsonObject json = null;
        try {
            json = weixinRequest(wxAuthTokenUrl.toString());
        } catch (BusinessException e) {
            e.printStackTrace();
        }
        String accessToken = json.get("access_token").getAsString();
        String openId = json.get("openid").getAsString();
        Map<String, String> resp = new HashMap<String, String>(2, 1.0f);
        resp.put("accessToken", accessToken);
        resp.put("openId", openId);
        return resp;
    }

    //根据openid以及accesstoken获取用户基本信息
    public Map<String, String> getUserInfo(Map<String, String> data) {

        StringBuilder userInfoUrl = new StringBuilder(WeiXinConfig.USER_INFO_URL);
        userInfoUrl.append("?access_token=").append(data.get("accessToken")).append("&openid=")
                .append(data.get("openId")).append("&lang=zh_CN");

        JsonObject json = null;
        try {
            if (log.isDebugEnabled()) {
                log.debug("msg userInfoUrl-->{}", userInfoUrl.toString());
            }
            json = weixinRequest(userInfoUrl.toString());
        } catch (BusinessException e) {
            e.printStackTrace();
        }

        if (log.isDebugEnabled()) {
            log.debug("msg userInfoUrl jsonjson-->{}", json);
        }
        String nickName = json.get("nickname").getAsString();
        String sex = json.get("sex").getAsString();
        String headimgurl = json.get("headimgurl").getAsString();

        Map<String, String> dataMap = new HashMap<String, String>();

        dataMap.put("openId", String.valueOf(data.get("openId")));
        dataMap.put("nickname", nickName);
        dataMap.put("sex", sex);
        dataMap.put("image", headimgurl);
        return dataMap;
    }

    public String getTicket() {
        String token = getWeiXinAccessToken();
        StringBuilder sbTicket = new StringBuilder();
        sbTicket.append(WeiXinConfig.SIGNATURE_URL).append("?");
        sbTicket.append("access_token=").append(token).append("&");
        sbTicket.append("type=").append(JSAPI_TYPE);

        String ticketResult = null;
        try {
            ticketResult = HttpClientUtils.sendGetSSLRequest(sbTicket.toString(), null);
        } catch (BusinessException e) {
            e.printStackTrace();
        }

        JSONObject jsonTicketObject = JSONObject.parseObject(ticketResult);
        String ticket = null;
        if (0 == jsonTicketObject.getIntValue("errcode")) {
            ticket = jsonTicketObject.getString("ticket");
            if (StringUtils.isNotBlank(ticket)) {
                Long ticketExpireTime = jsonTicketObject.getLong("expires_in");
                stringRedisTemplate.opsForValue().set(RedisKeyInfo.SIGNATURE_INFO.key(), ticket,
                        ticketExpireTime, TimeUnit.SECONDS);
            }
            return ticket;
        }
        else {
            log.error(jsonTicketObject.getString("errmsg"));
            return null;
        }
    }

    private JsonObject weixinRequest(String urlString) throws BusinessException {
        try {
            URL url = new URL(urlString);
            URLConnection connection = url.openConnection();
            connection.connect();
            BufferedReader in = new BufferedReader(new InputStreamReader(
                    connection.getInputStream()));
            String requestResult = "";
            String line = "";
            while ((line = in.readLine()) != null) {
                requestResult += line;
            }
            in.close();
            JsonObject json = new JsonParser().parse(requestResult).getAsJsonObject();
            if (log.isDebugEnabled()) {
                log.debug("msg userInfoUrl origin json-->{}", json);
            }
            return json;
        } catch (Exception e) {
            e.printStackTrace();
            throw new BusinessException(CodeConstant.SERVER_ERROR, "server error");
        }
    }

    public void sendMsg2Customer(Map<String, Object> msgMap) {

        if (msgMap == null || msgMap.isEmpty()) {
            return;
        }

        String accessToken = this.getWeiXinAccessToken();

        if (log.isDebugEnabled()) {
            log.debug("weixin accessToken { " + accessToken + " } ");
        }

        StringBuilder weixin2CustomerUrl = new StringBuilder(WeiXinConfig.CUSTOM_MSG);
        weixin2CustomerUrl.append("?access_token=").append(accessToken);

        Map<String, String> headerMap = new HashMap<String, String>();
        headerMap.put("Content-Type", "application/json");

        String resp = null;
        try {
            resp = com.ai.bitcoin.utils.HttpClientUtils.doPost(weixin2CustomerUrl.toString(), msgMap, headerMap);
        } catch (Exception e) {
            log.error("unexpect error for sending cmsg to customer", e);
            throw new RuntimeException("unexpect error for sending cmsg to customer");
        }
        log.info("sendMsg2Customer respm  { " + resp + " } ");

    }

    //有效时间为10分钟
    public Map<String, String> generateTemporyQrcode(Long expireSeconds, String prefix) {
        String accessToken = getWeiXinAccessToken();
        StringBuilder ticketReqURL = new StringBuilder();
        ticketReqURL.append(WeiXinConfig.QRCODE_TICKET_URL)
                .append("?").append("access_token=").append(accessToken);
        String sceneId = prefix + IdGeneration.getUniqueSign();
        StringBuilder sendData = new StringBuilder();
        sendData
                .append("{")
                .append("\"")
                .append("expire_seconds")
                .append("\"")
                .append(":")
                .append(expireSeconds)
                .append(",")
                .append("\"")
                .append("action_name")
                .append("\"")
                .append(":")
                .append("\"")
                .append(QrCodeConstant.TEMPORY_QRCODE_TYPE)
                .append("\"")
                .append(",")
                .append("\"")
                .append("action_info")
                .append("\"")
                .append(":")
                .append("{")
                .append("\"")
                .append("scene")
                .append("\"")
                .append(":")
                .append("{")
                .append("\"")
                .append("scene_str")
                .append("\"")
                .append(":")
                .append("\"")
                .append(sceneId)
                .append("\"")
                .append("}")
                .append("}")
                .append("}");
        String ticketResult = HttpClientUtils.sendJsonPostRequest(ticketReqURL.toString(), sendData.toString(), false);
        JSONObject jsonTicketObject = JSONObject.parseObject(ticketResult);
        String ticket = jsonTicketObject.getString("ticket");
        String qrcodeUrl = WeiXinConfig.QRCODE_PIC_URL + ticket;
        Map<String, String> data = new HashMap<>(2, 1.0f);
        data.put("key", sceneId);
        data.put("qrcode", qrcodeUrl);
        return data;
    }

    public String generatePermanentQrcode(String sceneStr) {
        String accessToken = getWeiXinAccessToken();
        StringBuilder ticketReqURL = new StringBuilder();
        ticketReqURL.append(WeiXinConfig.QRCODE_TICKET_URL)
                .append("?").append("access_token=").append(accessToken);
        StringBuilder sendData = new StringBuilder();
        sendData
                .append("{")
                .append("\"")
                .append("action_name")
                .append("\"")
                .append(":")
                .append("\"")
                .append(QrCodeConstant.PERMANENT_QRCODE_TYPE)
                .append("\"")
                .append(",")
                .append("\"")
                .append("action_info")
                .append("\"")
                .append(":")
                .append("{")
                .append("\"")
                .append("scene")
                .append("\"")
                .append(":")
                .append("{")
                .append("\"")
                .append("scene_str")
                .append("\"")
                .append(":")
                .append("\"")
                .append(sceneStr)
                .append("\"")
                .append("}")
                .append("}")
                .append("}");
        String ticketResult = HttpClientUtils.sendJsonPostRequest(ticketReqURL.toString(), sendData.toString(), false);
        JSONObject jsonTicketObject = JSONObject.parseObject(ticketResult);
        String ticket = jsonTicketObject.getString("ticket");
        String qrcodeUrl = WeiXinConfig.QRCODE_PIC_URL + ticket;
        return qrcodeUrl;
    }


    //设置微信菜单
    public Map<String, Object> setWeiXinMenu(Map<String, Object> parameterMap) {

        String token = getWeiXinAccessToken();
        if (token != null) {
            StringBuilder weixinMenuUrl = new StringBuilder(
                    WeiXinConfig.MENU_CREATE);
            weixinMenuUrl.append("?access_token=").append(token);

            if (log.isDebugEnabled()) {
                log.debug("weixin access token url { " + weixinMenuUrl.toString() + " }");
            }

            Map<String, String> headerMap = new HashMap<String, String>();
            headerMap.put("Content-Type", "application/json");

            String resp = null;
            try {
                resp = com.ai.bitcoin.utils.HttpClientUtils.doPost(weixinMenuUrl.toString(), parameterMap, headerMap);
            } catch (Exception e) {
                log.error("set weixin menu occured error  ", e);
                throw new RuntimeException("set weixin menu occured error");
            }

            if (StringUtils.isNotBlank(resp)) {
                //parse response data,
                if (log.isDebugEnabled()) {
                    log.debug("resp is " + resp);
                }
            }
            else {
                return null;
            }

            Map<String, Object> map = GsonUtil.fronJson2Map(resp);
            return map;

        }
        else {
            return null;
        }
    }

}
